﻿using System;
using System.IO;
using System.Net;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;
using System.Drawing;
using Kyoh.Lib.Plugin;

namespace Kyoh.App.Crawler.Plugin
{
    public abstract class TypicalParser : MarshalByRefObject, IParser
    {
        protected readonly Regex SupportedUriRegex;
        protected readonly Regex TitleRegex;
        protected readonly Regex ThumbnailRegex;
        protected readonly Regex ContentRegex;
        protected readonly Encoding Encoding;

        protected TypicalParser(string supportedUriPattern, string titlePattern, string thumbnailPattern, string contentPattern, Encoding encoding)
        {
            SupportedUriRegex = new Regex(supportedUriPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
            TitleRegex = new Regex(titlePattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
            ThumbnailRegex = new Regex(thumbnailPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
            ContentRegex = new Regex(contentPattern, RegexOptions.Compiled | RegexOptions.IgnoreCase | RegexOptions.ExplicitCapture);
            Encoding = encoding;
        }

        #region IParser メンバー
        public bool Supports(string pageUri)
        {
            return pageUri != null && SupportedUriRegex.IsMatch(pageUri);
        }
        public ILoader Parse(string pageUri)
        {
            return Reparse(pageUri);
        }

        protected abstract string GetExtension(string pageUri, string contentId, string title, string contentUri);
        protected abstract string ContentIdPrefix { get; }
        public ILoader Reparse(string pageUri)
        {
            if (pageUri == null)
                return null;
            var match = SupportedUriRegex.Match(pageUri);
            var fileName = ContentIdPrefix + match.Groups["contentId"].Value;
            if (!match.Success)
                return null;

            var contentId = match.Groups["contentId"].Value;
            var uri = match.Groups["uri"].Value;
            var req = (HttpWebRequest)WebRequest.Create(uri);
            using (var res = (HttpWebResponse)req.GetResponse())
            using (var reader = new StreamReader(res.GetResponseStream(), Encoding))
            {
                string title = null;
                string content = null;
                string thumbnail = null;
                bool titleFound = false;
                bool contentFound = false;
                bool thumbFound = false;
                string line;
                while (null != (line = reader.ReadLine()))
                {
                    var titleMatch = TitleRegex.Match(line);
                    var contentMatch = ContentRegex.Match(line);
                    var thumbMatch = ThumbnailRegex.Match(line);

                    if (!titleFound && titleMatch.Success)
                    {
                        title = titleMatch.Groups["title"].Value;
                        fileName = title + "_" + fileName;
                        titleFound = true;
                    }

                    if (!contentFound && contentMatch.Success)
                    {
                        content = HttpUtility.UrlDecode(contentMatch.Groups["content"].Value, Encoding);
                        contentFound = true;
                    }
                    if (!thumbFound && thumbMatch.Success)
                    {
                        thumbnail = HttpUtility.UrlDecode(thumbMatch.Groups["thumbnail"].Value, Encoding);
                        thumbFound = true;
                    }

                    if (titleFound && contentFound && thumbFound)
                        break;
                }

                if (contentFound)
                    return new DefaultLoader
                               {
                                   Title = title,
                                   FileName = fileName + "." + GetExtension(uri, contentId, title, content).TrimStart('.'),
                                   ContentUri = content,
                                   Thumbnail = thumbFound ? GetThumbnail(thumbnail, uri) : null,
                                   Uri = uri,
                               };
            }

            return null;
        }

        public static Image GetThumbnail(string thumbnail, string referer)
        {
            var req = (HttpWebRequest)WebRequest.Create(thumbnail);
            req.Referer = referer;
            using (var res = (HttpWebResponse)req.GetResponse())
            using (var reader = res.GetResponseStream())
                return Image.FromStream(reader);
        }

        #endregion

        public abstract string Author { get; }
        public abstract string Description { get; }
        public abstract Uri Uri { get; }

        public virtual object Preferences { get { return null; } set { } }
        public abstract string Name { get; }

        public void Dispose() { Dispose(true); }
        ~TypicalParser() { Dispose(false); }
        protected void Dispose(bool disposing) { }
    }
}
